package image

import (
	"context"
	"fmt"
	"github.com/TensShinet/IslandImage/registry"
	"github.com/Unixeno/islands/cmd/connection"
	"github.com/Unixeno/islands/pb"
	"github.com/spf13/cobra"
	"io/ioutil"
	"os"
)

var pullConf = registry.Config{}

func GetImagePullCmd() *cobra.Command {
	cmd := &cobra.Command{
		Use:   "pull name:tag",
		Short: "pull image from image repository",
		Args:  cobra.MinimumNArgs(1),
		Run:   imagePull,
	}

	flags := cmd.Flags()
	flags.BoolVar(&pullConf.UseHttp, "useHttp", false, "use HTTP to pull image")
	flags.BoolVar(&pullConf.Insecure, "insecure", false, "don't verify the ssl cert")
	flags.StringVar(&pullConf.Username, "username", "", "image repository's username")
	flags.StringVar(&pullConf.Password, "password", "", "image repository's password")
	flags.StringVar(&pullConf.Proxy, "proxy", "", "pull image proxy")

	return cmd
}

func imagePull(cmd *cobra.Command, args []string) {

	if len(args) < 1 {
		_ = cmd.Help()
		return
	}
	var err error
	defer func() {
		if err != nil {
			fmt.Printf("pull failed for the reason = %v\n", err)
		}
	}()
	imageName := args[0]

	tempDir, err := ioutil.TempDir("", "islandImage")
	defer os.RemoveAll(tempDir)
	pullConf.SaveDir = tempDir
	pullConf.ImageName = imageName
	r, err := registry.New(pullConf)

	if err != nil {
		return
	}

	manifest, err := r.GetManifest("")

	configFilePath, err := r.GetConfig(manifest)
	if err != nil {
		return
	}

	for {
		layers := make([]*pb.LayerInfo, len(manifest.Layers))
		for i, layer := range manifest.Layers {
			layers[i] = &pb.LayerInfo{
				Digest:    layer.Digest,
				Size:      int64(layer.Size),
				MediaType: layer.MediaType,
			}
		}
		resp, err := connection.Client.ImportImageWithNeed(context.Background(), &pb.ImportImageWithNeedReq{
			ConfigFilePath: configFilePath,
			Layers:         layers,
			ImageName:      r.ImageName,
			ImageTag:       r.ImageTag,
		})

		if err != nil {
			return
		}

		if resp.Imported {
			fmt.Println("SUCCESS IMPORT!")
			return
		}

		manifestLayers := make([]registry.ManifestLayer, len(resp.Layers))

		for i, layer := range resp.Layers {
			manifestLayers[i] = registry.ManifestLayer{
				Digest:    layer.Digest,
				MediaType: layer.MediaType,
				Size:      int(layer.Size),
			}
		}
		err = r.GetLayers(manifestLayers)

		if err != nil {
			return
		}
		_, err = connection.Client.ImportLayers(context.Background(), &pb.ImportLayersReq{
			LayersDir: tempDir,
			Layers:    resp.Layers,
		})

		if err != nil {
			return
		}
	}
}
